package com.aihna.mall.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.aihna.common.core.exception.ServiceException;
import com.aihna.common.core.utils.MapstructUtils;
import com.aihna.common.mybatis.core.page.TableDataInfo;
import com.aihna.common.mybatis.core.page.PageQuery;
import com.aihna.mall.constants.IntegralRecordConstants;
import com.aihna.mall.constants.StoreConstants;
import com.aihna.mall.domain.StoreUserBill;
import com.aihna.mall.domain.bo.*;
import com.aihna.mall.service.IStoreUserBillService;
import com.aihna.mall.service.IStoreUserIntegralRecordService;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.aihna.mall.domain.vo.StoreUserVo;
import com.aihna.mall.domain.StoreUser;
import com.aihna.mall.mapper.StoreUserMapper;
import com.aihna.mall.service.IStoreUserService;
import com.aihna.common.core.utils.StringUtils;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 会员用户Service业务层处理
 *
 * @author Joseph.Chen
 * @date 2024-04-14
 */
@RequiredArgsConstructor
@Service
public class StoreUserServiceImpl implements IStoreUserService {

    private final StoreUserMapper baseMapper;

    private final IStoreUserBillService storeUserBillService;

    private final IStoreUserIntegralRecordService storeUserIntegralRecordService;

    private final TransactionTemplate transactionTemplate;

    /**
     * 查询会员用户
     */
    @Override
    public StoreUserVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询会员用户列表
     */
    @Override
    public TableDataInfo<StoreUserVo> queryPageList(StoreUserBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<StoreUser> lqw = buildQueryWrapper(bo);
        Page<StoreUserVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询会员用户列表
     */
    @Override
    public List<StoreUserVo> queryList(StoreUserBo bo) {
        LambdaQueryWrapper<StoreUser> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<StoreUser> buildQueryWrapper(StoreUserBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<StoreUser> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getRealName()), StoreUser::getRealName, bo.getRealName());
        lqw.eq(bo.getBirthday() != null, StoreUser::getBirthday, bo.getBirthday());
        lqw.eq(StringUtils.isNotBlank(bo.getPhone()), StoreUser::getPhone, bo.getPhone());
        lqw.eq(bo.getLevel() != null, StoreUser::getLevel, bo.getLevel());
        lqw.eq(bo.getIsPromoter() != null, StoreUser::getIsPromoter, bo.getIsPromoter());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            StoreUser::getCreateTime ,params.get("beginCreateTime"), params.get("endCreateTime"));
        lqw.like(StringUtils.isNotBlank(bo.getSearchValue()), StoreUser::getNickname, bo.getSearchValue());
        lqw.like(StringUtils.isNotBlank(bo.getSearchValue()), StoreUser::getPhone, bo.getSearchValue());
        lqw.eq(bo.getSex() != null, StoreUser::getSex, bo.getSex());
        return lqw;
    }

    /**
     * 新增会员用户
     */
    @Override
    public Boolean insertByBo(StoreUserBo bo) {
        StoreUser add = MapstructUtils.convert(bo, StoreUser.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改会员用户
     */
    @Override
    public Boolean updateByBo(StoreUserBo bo) {
        StoreUser update = MapstructUtils.convert(bo, StoreUser.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(StoreUser entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除会员用户
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public Boolean updateUserPhone(Integer id, String phone) {
        StoreUser storeUser = baseMapper.selectById(id);
        if (ObjectUtil.isNull(storeUser)) {
            return false;
        }
        storeUser.setPhone(phone);
        return baseMapper.updateById(storeUser) > 0;
    }

    @Override
    public Boolean updateIntegralMoney(UserOperateIntegralMoneyBo bo) {
        if (ObjectUtil.isNull(bo.getMoneyValue()) || ObjectUtil.isNull(bo.getIntegralValue())) {
            throw new ServiceException("至少输入一个金额");
        }
        if (bo.getMoneyValue().compareTo(BigDecimal.ZERO) < 1 && bo.getIntegralValue() <= 0) {
            throw new ServiceException("修改值不能等小于等于0");
        }

        StoreUser storeUser = baseMapper.selectById(bo.getId());
        if (ObjectUtil.isNull(storeUser)) {
            throw new ServiceException("用户不存在");
        }

        // 减少时要判断小于0的情况,添加时判断是否超过数据限制
        if (bo.getMoneyType().equals(2) && bo.getMoneyValue().compareTo(BigDecimal.ZERO) != 0) {
            if (storeUser.getNowMoney().subtract(bo.getMoneyValue()).compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("余额扣减后不能小于0");
            }
        }
        if (bo.getMoneyType().equals(1) && bo.getMoneyValue().compareTo(BigDecimal.ZERO) != 0) {
            if (storeUser.getNowMoney().add(bo.getMoneyValue()).compareTo(new BigDecimal("99999999.99")) > 0) {
                throw new ServiceException("余额添加后后不能大于99999999.99");
            }
        }

        if (bo.getIntegralType().equals(2) && bo.getIntegralValue() != 0) {
            if (storeUser.getIntegral() - bo.getIntegralValue() < 0) {
                throw new ServiceException("积分扣减后不能小于0");
            }
        }
        if (bo.getIntegralType().equals(1) && bo.getIntegralValue() != 0) {
            if ((storeUser.getIntegral() + bo.getIntegralValue()) > 99999999) {
                throw new ServiceException("积分添加后不能大于99999999");
            }
        }

        Boolean execute = transactionTemplate.execute(e -> {
            // 处理余额
            if (bo.getMoneyValue().compareTo(BigDecimal.ZERO) > 0) {
                // 生成UserBill
                StoreUserBillBo userBill = new StoreUserBillBo();
                userBill.setUid(storeUser.getId());
                userBill.setLinkId("0");
                userBill.setTitle("后台操作");
                userBill.setCategory(StoreConstants.USER_BILL_CATEGORY_MONEY);
                userBill.setNumber(bo.getMoneyValue());
                userBill.setStatus(1);
                userBill.setCreateTime(DateUtil.date());

                if (bo.getMoneyType() == 1) {// 增加
                    userBill.setPm(1);
                    userBill.setType(StoreConstants.USER_BILL_TYPE_SYSTEM_ADD);
                    userBill.setBalance(storeUser.getNowMoney().add(bo.getMoneyValue()));
                    userBill.setMark(StrUtil.format("后台操作增加了{}余额", bo.getMoneyValue()));

                    storeUserBillService.insertByBo(userBill);
                    operationNowMoney(storeUser.getId(), bo.getMoneyValue(), storeUser.getNowMoney(), "add");
                } else {
                    userBill.setPm(0);
                    userBill.setType(StoreConstants.USER_BILL_TYPE_SYSTEM_SUB);
                    userBill.setBalance(storeUser.getNowMoney().subtract(bo.getMoneyValue()));
                    userBill.setMark(StrUtil.format("后台操作减少了{}余额", bo.getMoneyValue()));

                    storeUserBillService.insertByBo(userBill);
                    operationNowMoney(storeUser.getId(), bo.getMoneyValue(), storeUser.getNowMoney(), "sub");
                }
            }

            // 处理积分
            if (bo.getIntegralValue() > 0) {
                // 生成记录
                StoreUserIntegralRecordBo integralRecord = new StoreUserIntegralRecordBo();
                integralRecord.setUid(storeUser.getId());
                integralRecord.setLinkType(IntegralRecordConstants.INTEGRAL_RECORD_LINK_TYPE_SIGN);
                integralRecord.setTitle(IntegralRecordConstants.BROKERAGE_RECORD_TITLE_SYSTEM);
                integralRecord.setIntegral(bo.getIntegralValue());
                integralRecord.setStatus(IntegralRecordConstants.INTEGRAL_RECORD_STATUS_COMPLETE);
                if (bo.getIntegralType() == 1) {// 增加
                    integralRecord.setType(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_ADD);
                    integralRecord.setBalance(storeUser.getIntegral() + bo.getIntegralValue());
                    integralRecord.setMark(StrUtil.format("后台操作增加了{}积分", bo.getIntegralValue()));

                    operationIntegral(storeUser.getId(), bo.getIntegralValue(), storeUser.getIntegral(), "add");
                } else {
                    integralRecord.setType(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_SUB);
                    integralRecord.setBalance(storeUser.getIntegral() - bo.getIntegralValue());
                    integralRecord.setMark(StrUtil.format("后台操作减少了{}积分", bo.getIntegralValue()));
                    operationIntegral(storeUser.getId(), bo.getIntegralValue(), storeUser.getIntegral(), "sub");
                }
                storeUserIntegralRecordService.insertByBo(integralRecord);
            }
            return Boolean.TRUE;
        });

        if (!execute) {
            throw new ServiceException("修改积分/余额失败");
        }
        return execute;
    }

    @Override
    public Boolean updateSpread(UserUpdateSpreadBo bo) {
        Long userId = bo.getId();
        Long spreadUid = bo.getSpreadId();
        if (userId.equals(spreadUid)) {
            throw new ServiceException("上级推广人不能为自己");
        }
        StoreUser user = baseMapper.selectById(userId);
        if (ObjectUtil.isNull(user)) {
            throw new ServiceException("用户不存在");
        }
        if (user.getSpreadId().equals(spreadUid)) {
            throw new ServiceException("当前推广人已经是所选人");
        }

        Long oldSprUid = user.getSpreadId();
        StoreUser spreadUser = baseMapper.selectById(spreadUid);
        if (ObjectUtil.isNull(spreadUser)) {
            throw new ServiceException("上级用户不存在");
        }
        if (spreadUser.getSpreadId().equals(userId)) {
            throw new ServiceException("当前用户已是推广人的上级");
        }

        user.setSpreadId(spreadUid);
        user.setSpreadTime(DateUtil.date());
        Boolean execute = transactionTemplate.execute(e -> {
            baseMapper.updateById(user);
            //更新推广员推广数
            updateSpreadCountById(spreadUid, "add");
            if (oldSprUid > 0) {
                updateSpreadCountById(oldSprUid, "sub");
            }
            return Boolean.TRUE;
        });
        return execute;

    }

    @Override
    public StoreUserVo selectUserByPhone(String phoneNumber) {
        LambdaQueryWrapper<StoreUser> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(phoneNumber), StoreUser::getPhone, phoneNumber);
        //lqw.eq(StoreUser::getStatus, );
        return baseMapper.selectVoOne(lqw);
    }

    private Boolean updateSpreadCountById(Long id, String type) {
        UpdateWrapper<StoreUser> updateWrapper = new UpdateWrapper<>();
        if (type.equals("add")) {
            updateWrapper.setSql("spread_count = spread_count + 1");
        } else {
            updateWrapper.setSql("spread_count = spread_count - 1");
        }
        updateWrapper.eq("id", id);
        return baseMapper.update(updateWrapper) > 0;
    }

    /**
     * 添加/扣减积分
     *
     * @param id         用户id
     * @param integral    积分
     * @param nowIntegral 历史积分
     * @param type        类型：add—添加，sub—扣减
     * @return Boolean
     */
    private Boolean operationIntegral(Long id, Integer integral, Integer nowIntegral, String type) {
        UpdateWrapper<StoreUser> updateWrapper = new UpdateWrapper<>();
        if (type.equals("add")) {
            updateWrapper.setSql(StrUtil.format("integral = integral + {}", integral));
        } else {
            updateWrapper.setSql(StrUtil.format("integral = integral - {}", integral));
            updateWrapper.last(StrUtil.format(" and (integral - {} >= 0)", integral));
        }
        updateWrapper.eq("id", id);
        updateWrapper.eq("integral", nowIntegral);
        return baseMapper.update(updateWrapper) > 0;
    }

    /**
     * 添加/扣减余额
     *
     * @param id      用户id
     * @param price    金额
     * @param nowMoney 历史金额
     * @param type     类型：add—添加，sub—扣减
     */
    private Boolean operationNowMoney(Long id, BigDecimal price, BigDecimal nowMoney, String type) {
        UpdateWrapper<StoreUser> updateWrapper = new UpdateWrapper<>();
        if (type.equals("add")) {
            updateWrapper.setSql(StrUtil.format("now_money = now_money + {}", price));
        } else {
            updateWrapper.setSql(StrUtil.format("now_money = now_money - {}", price));
            updateWrapper.last(StrUtil.format(" and (now_money - {} >= 0)", price));
        }
        updateWrapper.eq("id", id);
        updateWrapper.eq("now_money", nowMoney);
        return baseMapper.update(updateWrapper) > 0;
    }


}
